//  EveSession.m
//  EVEMonX
//
//  Copyright Andrew Scherkus 2006. All rights reserved.

#import <OgreKit/OgreKit.h>
#import "EveSession.h"

@implementation EveSession

- (NSString*)currentlyTraining {
    return currentlyTraining_;
}
- (void)setCurrentlyTraining:(NSString*) skillName {
    if (currentlyTraining_ != skillName) {
        [currentlyTraining_ release];
        currentlyTraining_ = [skillName copy];
    }
}

- (int)targetLevel {
    return targetLevel_;
}
- (void)setTargetLevel:(int) level {
    if (level >= 0 && level <= 5) {
        targetLevel_ = level;
    }
}
- (BOOL)targetLevelEnabled {
    return FALSE;
}


- (NSString*)timeLeft {
    return timeLeft_;
}
- (void)setTimeLeft:(NSString*) time {
    if (timeLeft_ != time) {
        [timeLeft_ release];
        timeLeft_ = [time copy];
    }
}

- (NSString*)spDone {
    return spDone_;
}
- (void)setSpDone:(NSString*) sp {
    if (spDone_ != sp) {
        [spDone_ release];
        spDone_ = [sp copy];
    }
}

- (NSNumber*)percentageComplete {
    return percentageComplete_;
}
- (void)setPercentageComplete:(NSNumber*) pct {
    if (percentageComplete_ != pct) {
        [percentageComplete_ release];
        percentageComplete_ = [pct copy];
    }
}
- (BOOL)percentageCompleteEnabled {
    return FALSE;
}

- (void) dealloc {
    [self setCurrentlyTraining:nil];
    [self setTimeLeft:nil];
    [self setSpDone:nil];
    [self setPercentageComplete:nil];
    
    [super dealloc];
}

- (NSString*)getURL:(NSString*) urlString referer:(NSString*) refString {
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSHTTPURLResponse *response = [NSURLResponse alloc];
    NSError *error = [NSError alloc];

    // Store cookies in the header
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *cookies = [cookieStorage cookiesForURL:[NSURL URLWithString:@"http://myeve.eve-online.com/"]];
    if ([cookies count] > 0) {
        NSDictionary *headerFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
        NSEnumerator *keys = [headerFields keyEnumerator];
        id key;
        id value;
        while ((key = [keys nextObject])) {
            value = [headerFields objectForKey:key];
            NSLog(@"%@ = %@", key, value);
        }
        [request setAllHTTPHeaderFields:headerFields];
    }
    
    // Add referer to header
    if (refString) {
        [request setValue:refString forHTTPHeaderField:@"Referer"];
    }
    
    NSLog(@"Fetching %@", [request URL]);
    NSData *data = [NSURLConnection sendSynchronousRequest:request
            returningResponse:&response error:&error];
    
    int statusCode = [response statusCode];
    NSLog(@"HTTP %d", statusCode);
    
    // Check for HTTP Response 200
    if (statusCode != 200) {
        return nil;
    }
    // Check if we have content
    const void *bytes = [data bytes];
    if (!bytes) {
        return nil;
    }

    // List header fields
    NSDictionary *fields = [request allHTTPHeaderFields];
    NSEnumerator *keys = [fields keyEnumerator];
    id key;
    while ((key = [keys nextObject])) {
        NSLog(@"%@ = %@", key, [fields objectForKey:key]);
    }    
    
    return [NSString stringWithUTF8String:bytes];
}

- (NSString*)updateSessionData:(NSString*)username password:(NSString*)password {
    // Destroy the timer
    if (timeLeftTimer_) {
        [timeLeftTimer_ invalidate];
    }

    // Delete all existing cookies
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *cookies = [cookieStorage cookiesForURL:[NSURL URLWithString:@"http://myeve.eve-online.com/character/skilltree.asp"]];
    NSEnumerator *cookieEnum = [cookies objectEnumerator];
    NSHTTPCookie *cookie = nil;
    while ((cookie = [cookieEnum nextObject]) != nil) {
        [cookieStorage deleteCookie:cookie];
    }

    NSString *htmlBody;
    BOOL loggedIn = FALSE;
    
    // Login URL
    NSString *loginURL = [NSString stringWithFormat:@"https://myeve.eve-online.com/login.asp?username=%@&password=%@&login=Login&Check=OK&r=&t=",
        username, password];
    
    // Attempt to login
    htmlBody = [self getURL:loginURL referer:nil];
    if (!htmlBody) {
        return @"Error logging in.\n";
    }
            
    // Find the redirect
    NSString *redirectURL;
    {
        OGRegularExpression *regex = [OGRegularExpression regularExpressionWithString:@"document\\.onload=window\\.location\\.href='(.*?)';"];
        NSEnumerator *enumerator = [regex matchEnumeratorInString:htmlBody];
        OGRegularExpressionMatch *match;
        while ((match = [enumerator nextObject]) != nil) {
            redirectURL = [match substringAtIndex:1];
        }
    }
    if(!redirectURL) {
        return @"Error logging in.\n";
    }
    
    htmlBody = [self getURL:redirectURL referer:loginURL];
    
        
    htmlBody = [self getURL:@"http://myeve.eve-online.com/character/skilltree.asp" referer:@"http://myeve.eve-online.com/news.asp"];
    NSString *characterID;
    if (htmlBody) {
        OGRegularExpression *regex = [OGRegularExpression regularExpressionWithString:@"characterID=(\\d+)"];
        NSEnumerator *enumerator = [regex matchEnumeratorInString:htmlBody];
        OGRegularExpressionMatch *match;
        while ((match = [enumerator nextObject]) != nil) {
            loggedIn = TRUE;
            characterID = [match substringAtIndex:1];
            break;
        }
    }
    
    if (!loggedIn) {
        return @"Error retrieving character list.\n";
    }
    
    // Get character page
    NSString *characterURL = [NSString stringWithFormat:@"http://myeve.eve-online.com/character/skilltree.asp?characterID=%@", characterID];
    htmlBody = [self getURL:characterURL referer:@"http://myeve.eve-online.com/character/skilltree.asp"];
    if (!htmlBody) {
        return @"Error retrieving character information.\n";
    }
    
    // Parse out character skill information
    NSRange range = [htmlBody rangeOfString:@"Currently training to:"];
    if (range.length == NSNotFound) {
        return @"Currently not training a skill.\n";
    }
    
    NSMutableString *skills = [NSMutableString string];
    OGRegularExpression *regex = [OGRegularExpression regularExpressionWithString:
        @"<div><div style=\"float:right;\"><img alt=\"level (\\d)\" src=\"/bitmaps/character/level\\d[_act]*.gif\"></div><div style=\"line-height: 1.45em;font-size:11px\">([A-Za-z ]+) / <i>Rank (\\d) / SP: (\\d+) of (\\d+)</i></div></div><div><div style=\"line-height: 1.45em;margin-left:12px;font-size:11px\"><div><font color=\"gold\"><span class=\"navdot\">&middot;</span>Currently training to: </font><strong>level (\\d) </strong></div><div><font color=\"gold\"><span class=\"navdot\">&middot;</span>Time left: </font><strong>([0-9A-Za-z, ]+)</strong></div><div><font color=\"gold\"><span class=\"navdot\">&middot;</span>SP done: </font><strong>(\\d+) of (\\d+)</strong></div></div></div>"];
    NSEnumerator *enumerator = [regex matchEnumeratorInString:htmlBody];
    OGRegularExpressionMatch *match;
    while ((match = [enumerator nextObject]) != nil) {
        NSString *level     = [match substringAtIndex:1];
        NSString *skill     = [match substringAtIndex:2];
        NSString *rank      = [match substringAtIndex:3];
        NSString *startSP   = [match substringAtIndex:4];
        NSString *endSP     = [match substringAtIndex:5];
        
        [skills appendFormat:@"%@ / Rank %@ / Level %@ / SP: %@ of %@\n",
            skill, rank, level, startSP, endSP];

        NSString *training  = [match substringAtIndex:6];
        NSString *timeLeft  = [match substringAtIndex:7];
        NSString *doneSP    = [match substringAtIndex:8];
        NSString *ofSP      = [match substringAtIndex:9];
        
        [skills appendFormat:@"Currently training to: level %@\n", training];
        [skills appendFormat:@"Time left: %@\n", timeLeft];
        [skills appendFormat:@"SP done: %@ of %@\n", doneSP, ofSP];
        
        // Calculate completion date
        [completionDate_ release];
        completionDate_ = [[EveSession calculateCompletionDate:timeLeft] copy];
        
        // Parse out start/end SP values
        spTarget_ = [endSP intValue] - [startSP intValue];
        
        // Calculate SP per second
        int spCurrent = [doneSP intValue];
        int spRemaining = spTarget_ - spCurrent;
        NSTimeInterval timeRemaining = [completionDate_ timeIntervalSinceNow];
        spPerSecond_ = spRemaining / timeRemaining;
        
        // Update member variables
        [self setCurrentlyTraining:skill];
        [self setTargetLevel:[training intValue]];
        [self updateStatistics];
    }
    
    // Create the statistics updater
    SEL statsSelector = @selector(updateStatistics);
    NSMethodSignature *statsSignature = [EveSession instanceMethodSignatureForSelector:statsSelector];
    NSInvocation *statsInvocation = [NSInvocation invocationWithMethodSignature:statsSignature];
    [statsInvocation setTarget:self];
    [statsInvocation setSelector:statsSelector];
    timeLeftTimer_ = [NSTimer scheduledTimerWithTimeInterval:1 invocation:statsInvocation repeats:YES];
    
    return skills;
}

- (void)updateStatistics {
    NSTimeInterval timeLeft = [completionDate_ timeIntervalSinceNow];
    if (timeLeft <= 0) {
        timeLeft = 0;
    }
    
    [self updateSpDone:timeLeft];
    [self updatePercentageComplete:timeLeft];
    [self updateTimeLeft:timeLeft];

    // Skill has completed, destroy the timer and notify the user
    if (timeLeft == 0) {
        if (timeLeftTimer_) {
            [timeLeftTimer_ invalidate];
        } 
        [NSApp requestUserAttention:NSCriticalRequest];
    }
}

- (void)updatePercentageComplete:(NSTimeInterval) timeLeft {
    double pctDone = 100.0;
    if (timeLeft > 0) {
        pctDone = 100.0 * (spTarget_ - (timeLeft * spPerSecond_));
        pctDone = pctDone / (double)(spTarget_);
    }
    [self setPercentageComplete:[NSNumber numberWithDouble:pctDone]];
}

- (void)updateSpDone:(NSTimeInterval) timeLeft {
    int spCurrent = spTarget_;
    if (timeLeft > 0) {
        spCurrent = (int)(spTarget_ - (timeLeft * spPerSecond_));
    }
    
    [self setSpDone:[NSString stringWithFormat:@"%d / %d", spCurrent, spTarget_]];
}

- (void)updateTimeLeft:(NSTimeInterval) timeLeft {
    if (timeLeft <= 0) {
        [self setTimeLeft:@"Done!"];
        return;
    }

    int days = (int)(timeLeft / 86400);
    timeLeft -= days * 86400;
    int hours = (int)(timeLeft / 3600);
    timeLeft -= hours * 3600;
    int minutes = (int)(timeLeft / 60);
    timeLeft -= minutes * 60;
    int seconds = (int)(timeLeft);
    
    NSMutableString *timeLeftString = [NSMutableString string];
    if (days) {
        [timeLeftString appendFormat:@"%d day", days];
        if (days != 1) {
            [timeLeftString appendString:@"s"];
        }
        [timeLeftString appendString:@", "];
    }

    if (hours || [timeLeftString length] > 0) {
        [timeLeftString appendFormat:@"%d hour", hours];
        if (hours != 1) {
            [timeLeftString appendString:@"s"];
        }
        [timeLeftString appendString:@", "];
    }
    
    if (minutes || [timeLeftString length] > 0) {
        [timeLeftString appendFormat:@"%d minute", minutes];
        if (minutes != 1) {
            [timeLeftString appendString:@"s"];
        }
        [timeLeftString appendString:@", "];
    }
    
    if (seconds || [timeLeftString length] > 0) {
        [timeLeftString appendFormat:@"%d second", seconds];
        if (seconds != 1) {
            [timeLeftString appendString:@"s"];
        }
    }
    
    [self setTimeLeft:timeLeftString];

}


+ (NSDate*)calculateCompletionDate:(NSString *)timeLeft {
    NSLog(@"timeLeft = '%@'", timeLeft);
    if ([timeLeft compare:@"training complete"] == NSOrderedSame) {
        return [NSDate date];
    }

    OGRegularExpression *regex;
    OGRegularExpressionMatch *match;
    NSString *string;
    
    NSTimeInterval time = 0;

    // Parse days
    regex = [OGRegularExpression regularExpressionWithString: @"(\\d+) day[s]?"];
    match = [regex matchInString:timeLeft];
    string = [match substringAtIndex:1];
    if (string) {
        time += [string intValue] * 86400;
    }

    // Parse hours
    regex = [OGRegularExpression regularExpressionWithString: @"(\\d+) hour[s]?"];
    match = [regex matchInString:timeLeft];
    string = [match substringAtIndex:1];
    if (string) {
        time += [string intValue] * 3600;
    }
    
    // Parse minutes
    regex = [OGRegularExpression regularExpressionWithString: @"(\\d+) minute[s]?"];
    match = [regex matchInString:timeLeft];
    string = [match substringAtIndex:1];
    if (string) {
        time += [string intValue] * 60;
    }
    
    // Parse seconds
    regex = [OGRegularExpression regularExpressionWithString: @"(\\d+) second[s]?"];
    match = [regex matchInString:timeLeft];
    string = [match substringAtIndex:1];
    if (string) {
        time += [string intValue];
    }
    
    return [NSDate dateWithTimeIntervalSinceNow:time];
}

@end
